package com.laiketui.task.services.dubbo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.laiketui.common.api.PublicMchService;
import com.laiketui.common.api.PublicStockService;
import com.laiketui.common.api.PubliceService;
import com.laiketui.common.mapper.*;
import com.laiketui.common.utils.tool.ImgUploadUtils;
import com.laiketui.common.utils.tool.str.StringUtils;
import com.laiketui.core.cache.RedisUtil;
import com.laiketui.core.exception.LaiKeAPIException;
import com.laiketui.core.lktconst.GloabConst;
import com.laiketui.core.utils.algorithm.DataAlgorithmTool;
import com.laiketui.core.utils.okhttp.HttpUtils;
import com.laiketui.core.utils.tool.DateUtil;
import com.laiketui.core.utils.tool.SerializePhpUtils;
import com.laiketui.domain.config.ConfiGureModel;
import com.laiketui.domain.config.ConfigModel;
import com.laiketui.domain.config.JumpPathModel;
import com.laiketui.domain.config.SkuModel;
import com.laiketui.domain.distribution.DistributionIncomeModel;
import com.laiketui.domain.distribution.UserDistributionModel;
import com.laiketui.domain.home.SystemMessageModel;
import com.laiketui.domain.lktconst.DictionaryConst;
import com.laiketui.domain.lktconst.ErrorCode;
import com.laiketui.domain.log.SignRecordModel;
import com.laiketui.domain.mch.AdminModel;
import com.laiketui.domain.mch.CustomerModel;
import com.laiketui.domain.mch.MchConfigModel;
import com.laiketui.domain.mch.MchModel;
import com.laiketui.domain.product.ProductListModel;
import com.laiketui.domain.product.StockModel;
import com.laiketui.domain.product.TaoBaoWorkModel;
import com.laiketui.domain.task.TaoBaoModel;
import com.laiketui.domain.user.User;
import com.laiketui.task.services.interfaces.TaskService;
import com.laiketui.task.services.interfaces.plugin.SignTaskService;
import com.xxl.job.core.context.XxlJobHelper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 所有商城定时任务
 *
 * @author Trick
 * @date 2020/12/14 15:29
 */
@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    private PubliceService publiceService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private SignTaskService signTaskService;

    @Override
    public void taskStoreAll() throws LaiKeAPIException {
        List<ConfigModel> configModel = null;
        CustomerModel customerModel = null;
        try {
            XxlJobHelper.log("缓存商城id 开始执行!");
            if (redisUtil.hasKey(GloabConst.RedisHeaderKey.LKT_STOREID_EFFECTIVE_LIST)) {
                XxlJobHelper.log("商城id已存在缓存 获取缓存 下次刷新商城id剩余:{}!", redisUtil.getExpire(GloabConst.RedisHeaderKey.LKT_STOREID_EFFECTIVE_LIST));
            } else {
                XxlJobHelper.log("商城id已存在缓存 开始初始化缓存!");
                //获取所有商城
                configModel = configModelMapper.getConfigAllInfo();
                Set<Integer> storeIdList = new HashSet<>();
                for (ConfigModel config : configModel) {
                    //只有正常的店铺才走流程
                    customerModel = new CustomerModel();
                    customerModel.setId(config.getStore_id());
                    customerModel.setRecycle(DictionaryConst.ProductRecycle.NOT_STATUS);
                    customerModel.setStatus(0);
                    customerModel.setStatus(CustomerModel.CUSTOMER_STATUS_OPEN);
                    customerModel = customerModelMapper.selectOne(customerModel);
                    if (customerModel != null) {
                        storeIdList.add(customerModel.getId());
                    } else {
                        XxlJobHelper.log("商城被锁定或者已到期 商城id:{}", config.getId());
                    }
                }
                //缓存storeId集
                redisUtil.set(GloabConst.RedisHeaderKey.LKT_STOREID_EFFECTIVE_LIST, JSON.toJSONString(storeIdList), GloabConst.LktConfig.LOGIN_STORE_ID_EXISTENCE_TIME);
            }

            XxlJobHelper.log("缓存商城id 执行完毕!");
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log("商城定时任务 异常: " + e.getMessage());
        } finally {
            configModel = null;
            customerModel = null;
        }
    }

    @Override
    public List<Integer> getStoreIdAll() throws LaiKeAPIException {
        try {
            XxlJobHelper.log("缓存所有商城id 开始执行!");
            if (!redisUtil.hasKey(GloabConst.RedisHeaderKey.LKT_STOREID_EFFECTIVE_LIST)) {
                taskStoreAll();
            }
            String json = redisUtil.get(GloabConst.RedisHeaderKey.LKT_STOREID_EFFECTIVE_LIST).toString();
            List<Integer> storeIdList = JSON.parseObject(json, new TypeReference<List<Integer>>() {
            });
            XxlJobHelper.log("获取到商城id数量{}", storeIdList.size());
            return storeIdList;
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log("获取商城id 异常: " + e.getMessage());
        }
        XxlJobHelper.log("商城id缓存为空");
        throw new LaiKeAPIException("商城id缓存为空");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearMessageDay() throws LaiKeAPIException {
        ConfigModel configModel = null;
        List<Integer> storeIdList = null;
        try {
            XxlJobHelper.log("定时清空消息 开始执行!");
            storeIdList = getStoreIdAll();

            for (int storeId : storeIdList) {
                XxlJobHelper.log("===== 商城id{} 开始清空消息 ======", storeId);
                //获取商城配置信息
                configModel = new ConfigModel();
                configModel.setStore_id(storeId);
                configModel = configModelMapper.selectOne(configModel);
                if (configModel != null) {
                    Integer day = configModel.getMessage_day();
                    if (day != null && day > 0) {
                        //到期时间
                        Date endDate = DateUtil.getAddDate(-day);
                        XxlJobHelper.log("该商城消息保留的天数:{},消息过期时间{}", day, DateUtil.dateFormate(endDate, GloabConst.TimePattern.YMDHMS));
                        int count = systemMessageModelMapper.delMessageExpire(storeId, endDate);
                        XxlJobHelper.log("【总共清除{}条消息】", count);
                    } else {
                        XxlJobHelper.log("【该商城不删除消息】");
                    }
                } else {
                    XxlJobHelper.log("【该商城未配置信息】");
                }
                XxlJobHelper.log("===== 商城id{} 清空消息完成 ======", storeId);
            }
            XxlJobHelper.log("定时清空消息 执行完毕!");
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log("定时清空消息 异常: " + e.getMessage());
        } finally {
            storeIdList = null;
            configModel = null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reptilesTaoBao() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        List<Integer> taskWidList = null;
        TaoBaoWorkModel taoBaoWorkModel = null;
        List<TaoBaoModel> taoBaoModelList = null;
        TaoBaoModel updateTaoBao = null;
        try {
            XxlJobHelper.log("定时爬取淘宝数据 开始执行!");
            storeIdList = getStoreIdAll();
            for (int storeId : storeIdList) {
                XxlJobHelper.log("===== 商城id{} 开始定时爬取淘宝数据 ======", storeId);
                //获取待爬取的任务
                taoBaoModelList = taoBaoModelMapper.selectTaoBao(storeId, TaoBaoModel.TAOBAO_STATUS_TO_BE_OBTAINED);
                XxlJobHelper.log("待获取{}个任务", taoBaoModelList.size());
                taskWidList = new ArrayList<>();
                for (TaoBaoModel taobaoTask : taoBaoModelList) {
                    if (!taskWidList.contains(taobaoTask.getW_id())) {
                        //标记任务执行中
                        taoBaoWorkModel = new TaoBaoWorkModel();
                        taoBaoWorkModel.setId(taobaoTask.getW_id());
                        taoBaoWorkModel.setStatus(TaoBaoWorkModel.TAOBAO_STATUS_GETTING_ING);
                        int count = taoBaoWorkModelMapper.updateByPrimaryKeySelective(taoBaoWorkModel);
                        XxlJobHelper.log("任务总表wid{}标记状态【获取中】;执行结果:{}", taobaoTask.getW_id(), count > 0);
                        taskWidList.add(taobaoTask.getW_id());
                    }
                    //标记获取中
                    updateTaoBao = new TaoBaoModel();
                    updateTaoBao.setId(taobaoTask.getId());
                    updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_GETTING_ING);
                    int count = taoBaoModelMapper.updateByPrimaryKeySelective(updateTaoBao);
                    XxlJobHelper.log("淘宝任务id{},标记状态【获取中】;执行结果:{}", taobaoTask.getId(), count > 0);
                    getTaoBaoData(taobaoTask);
                }
                //标记执行完毕
                for (Integer taskWorkIds : taskWidList) {
                    taoBaoWorkModel = new TaoBaoWorkModel();
                    taoBaoWorkModel.setId(taskWorkIds);
                    taoBaoWorkModel.setStatus(TaoBaoWorkModel.TAOBAO_STATUS_CRAWLING_SUCCESS);
                    int count = taoBaoWorkModelMapper.updateByPrimaryKeySelective(taoBaoWorkModel);
                    XxlJobHelper.log("任务总表wid{}标记状态【执行完毕】;执行结果:{}", taskWorkIds, count > 0);
                }

                XxlJobHelper.log("===== 商城id{} 定时爬取淘宝数据完成 ======", storeId);
            }
            XxlJobHelper.log("定时爬取淘宝数据 执行完毕!");
        } catch (LaiKeAPIException l) {
            l.printStackTrace();
            XxlJobHelper.log("定时爬取淘宝数据 异常: " + l.getMessage());
            throw l;
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log("定时爬取淘宝数据 异常: " + e.getMessage());
        } finally {
            storeIdList = null;
            taskWidList = null;
            taoBaoWorkModel = null;
            taoBaoModelList = null;
            updateTaoBao = null;
        }
    }


    @Override
    public void resettingPwdNum() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        try {
            XxlJobHelper.log("定时重置密码次数 开始执行!");
            storeIdList = getStoreIdAll();
            for (int storeId : storeIdList) {
                XxlJobHelper.log("===== 商城id{} 开始重置密码次数 ======", storeId);
                int count = userBaseMapper.resettingPwdNum(storeId, DateUtil.dateFormate(new Date(), GloabConst.TimePattern.YMD));
                XxlJobHelper.log(">>>> 重置成功,重置数量:{} <<<<", count);
            }
            XxlJobHelper.log("定时重置密码次数 执行完毕!");
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log("定时重置密码次数 异常: " + e.getMessage());
        } finally {
            storeIdList = null;
        }
    }

    /**
     * 淘宝抓取商品
     * 【PublicGoodsServiceImpl.getTaoBaoData 请保持一致】
     *
     * @param taoBaoModel -
     * @throws LaiKeAPIException-
     * @author Trick
     * @date 2021/9/1 13:52
     */
    @Deprecated
    private void getTaoBaoData(TaoBaoModel taoBaoModel) throws LaiKeAPIException {
        TaoBaoModel updateTaoBao = new TaoBaoModel();
        //检查商品是否重复
        ProductListModel productListModel = new ProductListModel();
        //获取客户店铺信息
        AdminModel adminModel = new AdminModel();
        String imageUrl = null;
        //上传外链图片
        String imageName = null;
        String skuMapStr = null;
        //爬取的数据结构 - 所有规格排列组合信息
        Map<String, Map<String, Object>> skuJsonMap = null;
        String[][] groupNodes = null;
        //属性名称
        String attrName = null;
        Map<String, Object> attrMap = null;
        //节点id集合
        List<String> nodeIdAllList = null;
        SkuModel saveSkuModel = null;
        StringBuilder nodeIdstr = null;
        ConfiGureModel confiGureModel = null;
        StockModel stockModel = null;
        try {
            //标记获取中
            updateTaoBao.setId(taoBaoModel.getId());
            updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_GETTING_ING);
            taoBaoModelMapper.updateByPrimaryKeySelective(updateTaoBao);
            productListModel.setStore_id(taoBaoModel.getStore_id());
            productListModel.setProduct_number(taoBaoModel.getItemid());
            productListModel.setRecycle(DictionaryConst.ProductRecycle.NOT_STATUS.toString());
            int count = productListModelMapper.selectCount(productListModel);
            if (count < 0) {
                updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
                updateTaoBao.setMsg("请勿重复抓取");
                taoBaoModelMapper.updateByPrimaryKeySelective(updateTaoBao);
                XxlJobHelper.log("请勿重复抓取 商品参数:{}", JSON.toJSONString(productListModel));
                return;
            }

            adminModel.setStore_id(taoBaoModel.getStore_id());
            adminModel.setType(1);
            adminModel = adminModelMapper.selectOne(adminModel);
            if (adminModel == null) {
                XxlJobHelper.log("客户店铺不存在", JSON.toJSONString(adminModel));
                updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
                updateTaoBao.setMsg("业务数据错误");
                taoBaoModelMapper.updateByPrimaryKeySelective(updateTaoBao);
                return;
            }

            //开始获取淘宝商品数据
            String url = String.format(GloabConst.OtherUrl.API_TAOBAO_GOODSDATA_URL, taoBaoModel.getItemid());
            String detailUrl = String.format(GloabConst.OtherUrl.API_TAOBAO_GOODSDATA_DETAIL_URL, taoBaoModel.getItemid());
            //爬取网页
            Document goodsDetailDom = Jsoup.connect(detailUrl).get();
            Document document = Jsoup.connect(url).get();

            //获取页面所有属性类型>值
            Elements goodsAttrDom = document.select("#J_isku>.tb-skin>dl>dd>ul");
            if (goodsAttrDom.size() < 1) {
                XxlJobHelper.log("淘宝抓取失败 网页内容: {}", goodsAttrDom.html());
                XxlJobHelper.log(">>>>>商品规格信息爬取失败--【商品已经下架或者不是淘宝商品】<<<<<");
                updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
                updateTaoBao.setMsg("商品规格信息爬取失败【商品已经下架或者不是淘宝商品】");
                taoBaoModelMapper.updateByPrimaryKeySelective(updateTaoBao);
                return;
            }

            //保存商品
            ProductListModel saveProductListModel = new ProductListModel();
            saveProductListModel.setStore_id(taoBaoModel.getStore_id());
            saveProductListModel.setWeight("0");
            saveProductListModel.setScan(taoBaoModel.getItemid());
            saveProductListModel.setProduct_number(taoBaoModel.getItemid());
            saveProductListModel.setProduct_class(taoBaoModel.getCid());
            saveProductListModel.setBrand_id(taoBaoModel.getBrand_id());
            saveProductListModel.setFreight("0");
            saveProductListModel.setMch_id(adminModel.getShop_id());
            saveProductListModel.setMch_status(DictionaryConst.GoodsMchExameStatus.EXAME_PASS_STATUS.toString());
            saveProductListModel.setPublisher("task");
            saveProductListModel.setRichList("");
            //抓取的商品统一推荐
            saveProductListModel.setS_type(String.format(",%s,", DictionaryConst.LKT_SPLX_003));
            //抓取展示位置统一全部商品
            saveProductListModel.setShow_adr(String.format(",%s,", DictionaryConst.GoodsShowAdr.GOODSSHOWADR_DEFAULT));

            //产品详情
            saveProductListModel.setContent(getGoodsContext(document));
            //关键词
            String goodsKeywords = goodsDetailDom.getElementsByAttributeValue("name", "keywords").attr("content");
            saveProductListModel.setKeyword(goodsKeywords);

            //产品标题
            String goodsTitle = document.select("#J_Title>.tb-main-title").attr("data-title");
            saveProductListModel.setProduct_title(goodsTitle);

            //校验商品标题
            ProductListModel productListCount = new ProductListModel();
            productListCount.setProduct_title(goodsTitle);
            productListCount.setStore_id(taoBaoModel.getStore_id());
            productListCount.setRecycle(DictionaryConst.ProductRecycle.NOT_STATUS.toString());
            count = productListModelMapper.selectCount(productListCount);
            if (count > 0) {
                updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
                updateTaoBao.setMsg(String.format("商品【%s】 已存在", goodsTitle));
                return;
            }
            //产品图片
            Elements goodsImages = document.select("#J_UlThumb>li");
            //商品轮播图集
            List<String> goodsImageUrls = new ArrayList<>();
            for (Element element : goodsImages) {
                imageUrl = GloabConst.HttpProtocol.HTTPS + ":" + element.select("div>a>img").attr("data-src");
                imageUrl = imageUrl.replace(".jpg_50x50.jpg", ".jpg_250x250.jpg");
                //上传外链图片
                imageName = publiceService.uploadImage(imageUrl, GloabConst.UploadConfigConst.IMG_UPLOAD_OSS, Integer.parseInt(DictionaryConst.StoreSource.LKT_LY_001), taoBaoModel.getStore_id(), null);
                goodsImageUrls.add(ImgUploadUtils.getUrlImgByName(imageName, true));
            }
            //产品主图
            String goodsImageMain = document.getElementById("J_ImgBooth").attr("src");
            //上传产品主图
            String goodsImageMainName = publiceService.uploadImage(GloabConst.HttpProtocol.HTTPS + ":" + goodsImageMain, GloabConst.UploadConfigConst.IMG_UPLOAD_OSS, Integer.parseInt(DictionaryConst.StoreSource.LKT_LY_001), taoBaoModel.getStore_id(), null);
            saveProductListModel.setImgurl(ImgUploadUtils.getUrlImgByName(goodsImageMainName, true));
            saveProductListModel.setCover_map(saveProductListModel.getImgurl());

            //商品价格
            BigDecimal goodsPrice = new BigDecimal(document.select("#J_FrmBid>input[name='current_price']").attr("value"));
            //价格信息 a:5:{s:3:"cbj";s:3:"200";s:2:"yj";s:4:"2000";s:2:"sj";s:4:"1179";s:4:"unit";s:3:"件";s:5:"kucun";s:5:"10000";}
            Map<String, String> initialMap = new HashMap<>(16);
            initialMap.put("cbj", goodsPrice.toString());
            initialMap.put("yj", goodsPrice.toString());
            initialMap.put("sj", goodsPrice.toString());
            initialMap.put("unit", "件");
            initialMap.put("kucun", "0");
            saveProductListModel.setInitial(SerializePhpUtils.JavaSerializeByPhp(initialMap));

            //获取库存规格信息
            String pattern = "(?s)skuMap(.*?):(.*?)}\\);";
            Pattern r = Pattern.compile(pattern);
            Matcher m = r.matcher(document.html());
            while (m.find()) {
                XxlJobHelper.log(">>>>>网页爬取开始<<<<<");
                skuMapStr = "{" + StringUtils.trim(m.group());
                skuMapStr = skuMapStr.replace("skuMap", "\"skuMap\"");
                skuMapStr = skuMapStr.replace("propertyMemoMap", "\"propertyMemoMap\"");
                skuMapStr = skuMapStr.substring(0, skuMapStr.length() - 3);
                //爬取的数据结构 - 所有规格排列组合信息
                skuJsonMap = JSON.parseObject(skuMapStr, new TypeReference<Map<String, Map<String, Object>>>() {});
                //商品规格信息 结构: {;节点;节点;节点... : {价格信息}}
                Map<String, Object> skuMap = skuJsonMap.get("skuMap");

                groupNodes = new String[goodsAttrDom.size()][];
                int x = 0;
                for (Element attrNameAll : goodsAttrDom) {
                    XxlJobHelper.log(">>>网页父节点{}爬取开始<<<", x);
                    //属性名称
                    attrName = attrNameAll.attr("data-property");
                    //属性值节点
                    Elements goodsAttrValueDom = attrNameAll.select("li");
                    //属性集合
                    attrMap = new HashMap<>(16);
                    //节点id集合
                    nodeIdAllList = new ArrayList<>();
                    //属性名称_LKT_属性id
                    String attributeStr = "%s_LKT_%s";

                    //准备添加属性
                    saveSkuModel = new SkuModel();
                    saveSkuModel.setAdmin_name("task");
                    saveSkuModel.setStore_id(1);
                    //父级 属性在sku表里是否存在
                    Integer skuFatherId = skuModelMapper.getAttributeByName(1, DictionaryConst.SkuType.SKUTYPE_NAME, attrName, 0);
                    if (skuFatherId == null) {
                        //添加属性名称
                        saveSkuModel.setSid(0);
                        saveSkuModel.setName(attrName);
                        saveSkuModel.setType(DictionaryConst.SkuType.SKUTYPE_NAME);
                        saveSkuModel.setAdd_date(new Date());
                        saveSkuModel = publicStockService.saveSku(saveSkuModel, 0);
                        skuFatherId = saveSkuModel.getId();
                    }
                    //添加属性值
                    int i = 0;
                    for (Element attrValueAll : goodsAttrValueDom) {
                        XxlJobHelper.log(">>当前网页节点{}爬取开始<<", i);
                        String attrValue = attrValueAll.select("a>span").text();
                        //节点id
                        String nodeId = attrValueAll.attr("data-value");
                        //子集 属性在sku表里是否存在
                        Integer skuSonId = skuModelMapper.getAttributeByName(1, DictionaryConst.SkuType.SKUTYPE_VALUE, attrValue, skuFatherId);
                        if (skuSonId == null) {
                            //没有数据则添加
                            saveSkuModel.setSid(skuSonId);
                            saveSkuModel.setName(attrValue);
                            saveSkuModel.setType(DictionaryConst.SkuType.SKUTYPE_VALUE);
                            saveSkuModel.setAdd_date(new Date());
                            saveSkuModel = publicStockService.saveSku(saveSkuModel, i);
                            skuSonId = saveSkuModel.getId();
                            XxlJobHelper.log("属性值添加完成 id={} ", skuSonId);
                        } else {
                            XxlJobHelper.log("父级id{}下属性{}的id已存在,无需新增属性 ", skuFatherId, attrValue);
                        }
                        //结构: 网页节点属性id + {xxx_LKT_xxx}...
                        attrMap.put(String.format(attributeStr, attrName, skuFatherId), String.format(attributeStr, attrValue, skuSonId));
                        nodeIdAllList.add(nodeId + JSON.toJSONString(attrMap));
                        XxlJobHelper.log(">>当前网页节点{}爬取完成<<", i);
                        i++;
                    }
                    //解决组合少一个的情况
                    if (x == 0) {
                        nodeIdAllList.add("");
                    }
                    groupNodes[x] = nodeIdAllList.toArray(new String[0]);
                    XxlJobHelper.log(">>>网页父节点{}爬取完成<<<", x);
                    x++;
                }
                XxlJobHelper.log(">>>>>网页爬取完成<<<<<");
                XxlJobHelper.log(">>>>>商品发布开始<<<<<");
                //发布商品
                int sort = productListModelMapper.getGoodsMaxSort(taoBaoModel.getStore_id());
                saveProductListModel.setLabel("");
                saveProductListModel.setSort(sort);
                saveProductListModel.setAdd_date(new Date());
                count = productListModelMapper.insertSelective(saveProductListModel);
                if (count < 1) {
                    updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
                    updateTaoBao.setMsg("商品保存失败");
                    throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_SPBCSB, "商品保存失败", "getTaoBaoData");
                }
                //添加轮播图
                publiceService.addRotationImage(goodsImageUrls, saveProductListModel.getId(), false);

                XxlJobHelper.log(">>>>>商品发布成功 id={}<<<<<", saveProductListModel.getId());
                //获取所有可能的组合价格信息
                List<List<String>> resultList = new ArrayList<>();
                DataAlgorithmTool.combination(groupNodes, new String[groupNodes.length], 0, 0, resultList);
                if (resultList.size() > 0) {
                    resultList.remove(resultList.size() - 1);
                }
                //添加规格库存信息
                for (List<String> groupNodeId : resultList) {
                    nodeIdstr = new StringBuilder();
                    //因为网页里是用‘;’来分隔做key
                    nodeIdstr.append(";");
                    for (String nodeId : groupNodeId) {
                        nodeIdstr.append(nodeId).append(";");
                    }
                    //拆分
                    Map<String, String> nodeIdMap = StringUtils.getSplit(nodeIdstr.toString(), "{", "}", ",");
                    for (String key : nodeIdMap.keySet()) {
                        String valueJson = "[" + nodeIdMap.get(key) + "]";
                        XxlJobHelper.log(">>>添加规格库存开始 {}<<<", nodeIdMap.get(key));
                        //找到当前id价格信息
                        if (skuMap.containsKey(key)) {
                            confiGureModel = new ConfiGureModel();
                            //获取属性
                            List<Map<String, String>> attributeList = JSON.parseObject(valueJson, new TypeReference<List<Map<String, String>>>() {
                            });
                            Map<String, String> attributeMap = new HashMap<>(16);
                            for (Map<String, String> map : attributeList) {
                                attributeMap.putAll(map);
                            }
                            //获取当前属性节点价格信息
                            Map<String, Object> goodsStockMap = JSON.parseObject(String.valueOf(skuMap.get(key)), new TypeReference<Map<String, Object>>() {
                            });
                            BigDecimal price = new BigDecimal(String.valueOf(goodsStockMap.get("price")));
                            String num = String.valueOf(goodsStockMap.get("stock"));
                            //下载规格图片
                            String attrImgUrlPath = "";
                            XxlJobHelper.log("↓↓↓↓↓ 正在下载规格图片 url:{} ↓↓↓↓↓", url);
                            String attrImgId = StringUtils.trim(key, ";");
                            String[] tempIds = attrImgId.split(";");
                            attrImgId = tempIds[1];
                            String tempUrl = document.select(String.format("#J_isku>.tb-skin>dl>dd>ul>li[data-value='%s']>a", attrImgId)).attr("style");
                            String pattern1 = "\\((.*?)\\)";
                            Pattern r1 = Pattern.compile(pattern1);
                            Matcher m1 = r1.matcher(tempUrl);
                            while (m1.find()) {
                                String path = m1.group();
                                attrImgUrlPath = GloabConst.HttpProtocol.HTTPS + ":" + path.substring(1, path.length() - 1);
                                attrImgUrlPath = attrImgUrlPath.replace(".jpg_30x30", ".jpg_200x200");
                                XxlJobHelper.log("正在上传规格图片 url:{}", attrImgUrlPath);
                                attrImgUrlPath = publiceService.uploadImage(attrImgUrlPath, GloabConst.UploadConfigConst.IMG_UPLOAD_OSS, Integer.parseInt(DictionaryConst.StoreSource.LKT_LY_001), taoBaoModel.getStore_id(), null);
                                XxlJobHelper.log("上传后的规格图片 url:{}", attrImgUrlPath);
                            }
                            XxlJobHelper.log("↓↓↓↓↓ 正在下载规格图片 完成 ↓↓↓↓↓");
                            //添加属性
                            confiGureModel.setPid(saveProductListModel.getId());
                            confiGureModel.setCostprice(price);
                            confiGureModel.setPrice(price);
                            confiGureModel.setYprice(price);
                            confiGureModel.setImg(ImgUploadUtils.getUrlImgByName(attrImgUrlPath, true));
                            confiGureModel.setMin_inventory(10);
                            confiGureModel.setTotal_num(Integer.parseInt(num));
                            confiGureModel.setNum(Integer.parseInt(num));
                            confiGureModel.setUnit("件");
                            confiGureModel.setBar_code(taoBaoModel.getItemid());
                            confiGureModel.setBargain_price(price);
                            confiGureModel.setStatus("0");
                            confiGureModel.setColor("");
                            confiGureModel.setAttribute(SerializePhpUtils.JavaSerializeByPhp(attributeMap));
                            confiGureModel.setCtime(new Date());
                            count = confiGureModelMapper.insertSelective(confiGureModel);
                            if (count < 1) {
                                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_SPGGKCBCSB, "商品规格库存保存失败", "getTaoBaoData");
                            }
                            //添加库存
                            stockModel = new StockModel();
                            stockModel.setStore_id(taoBaoModel.getStore_id());
                            stockModel.setProduct_id(saveProductListModel.getId());
                            stockModel.setAttribute_id(confiGureModel.getId());
                            stockModel.setFlowing_num(confiGureModel.getNum());
                            stockModel.setTotal_num(confiGureModel.getTotal_num());
                            stockModel.setContent("添加库存");
                            stockModel.setType(StockModel.StockType.STOCKTYPE_WAREHOUSING);
                            if (confiGureModel.getMin_inventory() >= confiGureModel.getNum()) {
                                stockModel.setContent("库存预警");
                                stockModel.setType(StockModel.StockType.AGREEMENTTYPE_WAREHOUSING_WARNING);
                            }
                            stockModel.setAdd_date(new Date());
                            count = stockModelMapper.insertSelective(stockModel);
                            if (count < 1) {
                                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_SPGGKCJLXXBCSB, "商品规格库存记录信息保存失败", "getTaoBaoData");
                            }

                            XxlJobHelper.log(">>>添加规格库存成功 id={}<<<", confiGureModel.getId());
                        } else {
                            XxlJobHelper.log(">>>未获取到当前节点价格信息 节点id={}<<<", key);
                        }
                    }
                    XxlJobHelper.log(">>>>添加规格库存结束<<<<");
                }
            }
            updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_SUCCESS);
        } catch (NullPointerException nul) {
            updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
            updateTaoBao.setMsg("抓取失败，某数据为空!");
            XxlJobHelper.handleFail("爬取淘宝数据 异常: ", nul);
            XxlJobHelper.handleFail(nul);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        } catch (LaiKeAPIException l) {
            updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
            updateTaoBao.setMsg(l.getMessage());
            XxlJobHelper.handleFail("爬取淘宝数据 异常: ", l.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        } catch (Exception e) {
            updateTaoBao.setStatus(TaoBaoModel.TAOBAO_STATUS_CRAWLING_FAIL);
            updateTaoBao.setMsg("淘宝抓取失败!");
            e.printStackTrace();
            XxlJobHelper.handleFail("爬取淘宝数据 异常: ", e);
            XxlJobHelper.handleFail(e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        } finally {
            int count = taoBaoModelMapper.updateByPrimaryKeySelective(updateTaoBao);
            if (TaoBaoModel.TAOBAO_STATUS_CRAWLING_SUCCESS.equals(updateTaoBao.getStatus())) {
                XxlJobHelper.log(">>>>>>>标记获取状态 结果{}<<<<<<<", count > 0);
            } else {
                XxlJobHelper.log(">>>>>>>标记获取状态 结果 【异常失败】<<<<<<<");
            }
            updateTaoBao = null;
            //检查商品是否重复
            productListModel = null;
            //获取客户店铺信息
            adminModel = null;
            imageUrl = null;
            //上传外链图片
            imageName = null;
            skuMapStr = null;
            //爬取的数据结构 - 所有规格排列组合信息
            skuJsonMap = null;
            groupNodes = null;
            //属性名称
            attrName = null;
            attrMap = null;
            //节点id集合
            nodeIdAllList = null;
            saveSkuModel = null;
            nodeIdstr = null;
            confiGureModel = null;
            stockModel = null;
        }
    }

    /**
     * 获取商品明细
     *
     * @param dom -
     * @throws LaiKeAPIException-
     * @author Trick
     * @date 2021/7/6 10:58
     */
    private String getGoodsContext(Document dom) throws LaiKeAPIException {
        StringBuilder content = new StringBuilder();
        try {
            String pattern = "(?s)apiImgInfo(.*?):(.*?),";
            Pattern r = Pattern.compile(pattern);
            Matcher m = r.matcher(dom.getElementsByTag("script").html());
            String imgUrlApi = "https://gd1.alicdn.com/imgextra/%s";
            Map<String, Object> imgUrlMap = new HashMap<>(16);
            while (m.find()) {
                String imgUrlApiJson = "{" + StringUtils.trim(m.group()).replace(",", "}");
                Map<String, String> imgUrlApiMap = new HashMap<>(16);
                imgUrlApiMap = JSON.parseObject(imgUrlApiJson, new TypeReference<Map<String, String>>() {
                });
                String goodsImgUrlApi = GloabConst.HttpProtocol.HTTPS + ":" + imgUrlApiMap.get("apiImgInfo");
                String resultJson = HttpUtils.get(goodsImgUrlApi);
                resultJson = resultJson.replace("$callback(", "");
                resultJson = resultJson.substring(0, resultJson.length() - 1);
                imgUrlMap = JSON.parseObject(resultJson, new TypeReference<Map<String, Object>>() {
                });
            }
            content.append("<p>");
            for (String key : imgUrlMap.keySet()) {
                if (key.length() > 10) {
                    content.append("<img src=\"").append(String.format(imgUrlApi, key)).append("\">");
                }
            }
            content.append("</p>");
        } catch (Exception e) {
            XxlJobHelper.handleFail(">>>>>>>抓取商品详情 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_SPGGKCBCSB, "商品规格库存保存失败", "getGoodsContext");
        }
        return content.toString();
    }

    public static void main(String[] args) throws IOException {

        String url = String.format(GloabConst.OtherUrl.API_TAOBAO_GOODSDATA_URL, "601086843322");
        Document document = Jsoup.connect(url).get();

        Elements goodsAttrDom = document.select("#J_isku>.tb-skin>dl>dd>ul");
        //获取库存规格信息
        String pattern = "(?s)skuMap(.*?):(.*?)}\\);";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(document.html());
        while (m.find()) {
            XxlJobHelper.log(">>>>>网页爬取开始<<<<<");
            String skuMapStr = "{" + StringUtils.trim(m.group());
            skuMapStr = skuMapStr.replace("skuMap", "\"skuMap\"");
            skuMapStr = skuMapStr.replace("propertyMemoMap", "\"propertyMemoMap\"");
            skuMapStr = skuMapStr.substring(0, skuMapStr.length() - 3);
            //爬取的数据结构 - 所有规格排列组合信息
            Map<String, Map<String, Object>> skuJsonMap = JSON.parseObject(skuMapStr, new TypeReference<Map<String, Map<String, Object>>>() {
            });
            //商品规格信息 结构: {;节点;节点;节点... : {价格信息}}
            Map<String, Object> skuMap = skuJsonMap.get("skuMap");

            String[][] groupNodes = new String[goodsAttrDom.size()][];
            int x = 0;
            for (Element attrNameAll : goodsAttrDom) {
                XxlJobHelper.log(">>>网页父节点{}爬取开始<<<", x);
                //属性名称
                String attrName = attrNameAll.attr("data-property");
                //属性值节点
                Elements goodsAttrValueDom = attrNameAll.select("li");
                //属性集合
                Map<String, Object> attrMap = new HashMap<>(16);
                //节点id集合
                List<String> nodeIdAllList = new ArrayList<>();
                //属性名称_LKT_属性id
                String attributeStr = "%s_LKT_%s";

                //准备添加属性
                SkuModel saveSkuModel = new SkuModel();
                saveSkuModel.setAdmin_name("task");
                saveSkuModel.setStore_id(1);
                //添加属性值
                int i = 0;
                for (Element attrValueAll : goodsAttrValueDom) {
                    XxlJobHelper.log(">>当前网页节点{}爬取开始<<", i);
                    String attrValue = attrValueAll.select("a>span").text();
                    //节点id
                    String nodeId = attrValueAll.attr("data-value");
                    //子集 属性在sku表里是否存在
                    nodeIdAllList.add(nodeId + JSON.toJSONString(attrMap));
                    XxlJobHelper.log(">>当前网页节点{}爬取完成<<", i);
                    i++;
                }
                //解决组合少一个的情况
                if (x == 0) {
                    nodeIdAllList.add("");
                }
                groupNodes[x] = nodeIdAllList.toArray(new String[0]);
                XxlJobHelper.log(">>>网页父节点{}爬取完成<<<", x);
                x++;
            }
            XxlJobHelper.log(">>>>>网页爬取完成<<<<<");
            XxlJobHelper.log(">>>>>商品发布开始<<<<<");

            //获取所有可能的组合价格信息
            List<List<String>> resultList = new ArrayList<>();
            DataAlgorithmTool.combination(groupNodes, new String[groupNodes.length], 0, 0, resultList);
            if (resultList.size() > 0) {
                resultList.remove(resultList.size() - 1);
            }
            //添加规格库存信息
            for (List<String> groupNodeId : resultList) {
                StringBuilder nodeIdstr = new StringBuilder();
                //因为网页里是用‘;’来分隔做key
                nodeIdstr.append(";");
                for (String nodeId : groupNodeId) {
                    nodeIdstr.append(nodeId).append(";");
                }
                //拆分
                Map<String, String> nodeIdMap = StringUtils.getSplit(nodeIdstr.toString(), "{", "}", ",");
                for (String key : nodeIdMap.keySet()) {
                    String attrImgId = StringUtils.trim(key, ";");
                    String[] tempIds = attrImgId.split(";");
                    attrImgId = tempIds[1];
                    String tempUrl = document.select(String.format("#J_isku>.tb-skin>dl>dd>ul>li[data-value='%s']>a", attrImgId)).attr("style");
                    System.out.println(tempUrl.trim());

                    String pattern1 = "\\((.*?)\\)";
                    Pattern r1 = Pattern.compile(pattern1);
                    Matcher m1 = r1.matcher(tempUrl);
                    while (m1.find()) {
                        String path = m1.group();
                        String attrImgUrlPath = GloabConst.HttpProtocol.HTTPS + ":" + path.substring(1, path.length() - 1);
                        attrImgUrlPath = attrImgUrlPath.replace(".jpg_30x30", ".jpg_200x200");
                        System.out.println(attrImgUrlPath);
                    }

                    String valueJson = "[" + nodeIdMap.get(key) + "]";
                    XxlJobHelper.log(">>>添加规格库存开始 {}<<<", nodeIdMap.get(key));
                    //找到当前id价格信息
                    if (skuMap.containsKey(key)) {
                        //获取属性
                        List<Map<String, String>> attributeList = JSON.parseObject(valueJson, new TypeReference<List<Map<String, String>>>() {
                        });
                        Map<String, String> attributeMap = new HashMap<>(16);
                        for (Map<String, String> map : attributeList) {
                            attributeMap.putAll(map);
                        }
                        //获取当前属性节点价格信息
                        Map<String, Object> goodsStockMap = JSON.parseObject(String.valueOf(skuMap.get(key)), new TypeReference<Map<String, Object>>() {
                        });
                        BigDecimal price = new BigDecimal(String.valueOf(goodsStockMap.get("price")));
                        String num = String.valueOf(goodsStockMap.get("stock"));
                        //添加属性
                        ConfiGureModel confiGureModel = new ConfiGureModel();
                        confiGureModel.setCostprice(price);
                        confiGureModel.setPrice(price);
                        confiGureModel.setYprice(price);
                        confiGureModel.setImg("图片url");
                        confiGureModel.setMin_inventory(10);
                        confiGureModel.setTotal_num(Integer.parseInt(num));
                        confiGureModel.setNum(Integer.parseInt(num));
                        confiGureModel.setUnit("件");
                        confiGureModel.setBargain_price(price);
                        confiGureModel.setStatus("0");
                        confiGureModel.setColor("");
                        confiGureModel.setAttribute(SerializePhpUtils.JavaSerializeByPhp(attributeMap));
                        confiGureModel.setCtime(new Date());
                        //添加库存
                        StockModel stockModel = new StockModel();
                        stockModel.setAttribute_id(confiGureModel.getId());
                        stockModel.setFlowing_num(confiGureModel.getNum());
                        stockModel.setTotal_num(confiGureModel.getTotal_num());
                        stockModel.setContent("添加库存");
                        stockModel.setType(StockModel.StockType.STOCKTYPE_WAREHOUSING);
                        if (confiGureModel.getMin_inventory() >= confiGureModel.getNum()) {
                            stockModel.setContent("库存预警");
                            stockModel.setType(StockModel.StockType.AGREEMENTTYPE_WAREHOUSING_WARNING);
                        }
                        stockModel.setAdd_date(new Date());

                        XxlJobHelper.log(">>>添加规格库存成功 id={}<<<", confiGureModel.getId());
                    } else {
                        XxlJobHelper.log(">>>未获取到当前节点价格信息 节点id={}<<<", key);
                    }
                }
                XxlJobHelper.log(">>>>添加规格库存结束<<<<");
            }
        }

    }

    @Override
    public void signTask() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        try {
            XxlJobHelper.log("定时处理签到 开始执行!");
            storeIdList = getStoreIdAll();
            for (int storeId : storeIdList) {
                XxlJobHelper.log("===== 商城id{} 定时处理签到 ======", storeId);
                signTaskService.task(storeId);
                XxlJobHelper.log(">>>> 签到活动处理完毕 <<<<");
            }
            XxlJobHelper.log("定时处理签到 执行完毕!");
            XxlJobHelper.handleSuccess();
        } catch (Exception e) {
            XxlJobHelper.handleFail(">>>>>>>定时处理签到 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSCLQDYC, "定时处理签到 异常", "getGoodsContext");
        } finally{
            storeIdList = null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementIntegral() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        Date sysDate = null;
        try {
            XxlJobHelper.log("定时结算积分 开始执行!");
            int row;
            storeIdList =  getStoreIdAll();
            for (int storeId : storeIdList) {
                XxlJobHelper.log("==================== 商城id={} 定时结算积分 ====================", storeId);
                sysDate = new Date();
                //积分解冻结算
                row = signRecordModelMapper.setFrozenIntegral(storeId, sysDate, SignRecordModel.ScoreType.INTEGRAL_FROZEN, SignRecordModel.ScoreType.VIP_BUY);
                XxlJobHelper.log("积分解冻结算 执行结果:{}", row);
                //结算扣除用户过期积分
                row = signRecordModelMapper.settlementIntegral(storeId, sysDate);
                XxlJobHelper.log("扣除用户过期积分 执行结果:{}", row);
                //失效积分
                row = signRecordModelMapper.userInvalidScore(sysDate);
                XxlJobHelper.log("失效积分 执行结果:{}", row);
                XxlJobHelper.log("==================== 定时结算积分执行完成 ====================");
            }
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail(">>>>>>>定时结算积分 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSJSJFYC, "定时结算积分 异常", "settlementIntegral");
        } finally{
            sysDate = null;
            storeIdList = null;
        }
    }


    @Override
    public void cancellationShop() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        try {
            XxlJobHelper.log("定时清理店铺 开始执行!");
            storeIdList = getStoreIdAll();
            for (int storeId : storeIdList) {
                XxlJobHelper.log("==================== 商城id={} 定时清理店铺 ====================", storeId);
                //获取商城设置的删除时间 0 代表永不删除
                MchConfigModel mchConfigModel = null;
                try {
                    mchConfigModel = publicMchService.getMchConfig(storeId, customerModelMapper.getStoreMchId(storeId));
                } catch (LaiKeAPIException l) {
                    XxlJobHelper.log("====== 商城id={} 自营店设置不存在 =====", storeId);
                }
                if (mchConfigModel != null && mchConfigModel.getDelete_settings() != 0) {
                    XxlJobHelper.log("====== 商城id={} 设置的时间为{}个月未登录的店铺 =====", storeId, mchConfigModel.getDelete_settings());
                    //获取当前商城除了自营店其它所有店铺
                    List<Integer> mchIdList = mchModelMapper.getMchIdListByStoreId(storeId, mchConfigModel.getDelete_settings());
                    for (Integer mchId : mchIdList) {
                        XxlJobHelper.log("= 店铺{}主人已经{}个月没登陆了,开始清理... =", mchId, mchConfigModel.getDelete_settings());
                        String result = GloabConst.ManaValue.MANA_VALUE_SUCCESS;
                        try {
                            publicMchService.cancellationShop(storeId, mchId);
                        } catch (Exception e) {
                            result = e.getMessage();
                            XxlJobHelper.log("清理失败,原因:{}", result);
                        }
                        XxlJobHelper.log("定时删除店铺 店铺id{} 执行结果:{}", mchId, result);
                        result = null;
                    }
                    mchIdList = null;
                } else {
                    XxlJobHelper.log("商城{} 没有设置定时删除店铺", storeId);
                }
                mchConfigModel = null;
                XxlJobHelper.log("==================== 定时清理店铺 执行完成 ====================");
            }

        } catch (Exception e) {
            XxlJobHelper.handleFail(">>>>>>>定时清理店铺 【异常失败】<<<<<<<", e);
            XxlJobHelper.handleFail(">>>>>>>定时清理店铺 【异常失败】<<<<<<<");
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSQLDPYC, "定时清理店铺 异常", "cancellationShop");
        } finally {
            storeIdList = null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void memberExpirationProcessing() throws LaiKeAPIException {
        User user = null;
        List<User> select = null;
        try {
            XxlJobHelper.log("会员过期处理定时任务 开始执行!");
            user = new User();
            user.setGrade(User.MEMBER);
            select = userBaseMapper.select(user);
            select.stream().forEach(userBase -> {
                XxlJobHelper.log("==================== 正在处理会员用户{} ====================", userBase.getUser_id());
                boolean compare = DateUtil.dateCompare(new Date(), userBase.getGrade_end());
                if (compare) {
                    XxlJobHelper.log("==================== 会员用户{}已过期 ====================", userBase.getUser_id());
                    int i = userBaseMapper.memberExpirationProcessing(userBase.getStore_id(), userBase.getUser_id());
                    SystemMessageModel systemMessageSave = new SystemMessageModel();
                    systemMessageSave.setType(SystemMessageModel.ReadType.UNREAD);
                    systemMessageSave.setSenderid("admin");
                    systemMessageSave.setStore_id(userBase.getStore_id());
                    systemMessageSave.setRecipientid(userBase.getUser_id());
                    systemMessageSave.setTitle("系统消息");
                    systemMessageSave.setContent("您的会员已到期，续费后可继续享受会员权益！");
                    systemMessageSave.setTime(new Date());
                    systemMessageModelMapper.insertSelective(systemMessageSave);
                    XxlJobHelper.log("会员用户{} 执行结果:{}", userBase.getUser_id(), i);
                } else {
                    XxlJobHelper.log("==================== 会员用户{}未过期 ====================", userBase.getUser_id());
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail(">>>>>>>会员过期处理定时任务 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSJSJFYC, "会员过期处理定时任务 异常", "memberExpirationProcessing");
        } finally {
            user = null;
            select = null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mchAutoExamine() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        MchConfigModel mchConfigModel = null;
        try {
            XxlJobHelper.log("店铺自动审核成功处理定时任务 开始执行!");
            storeIdList = getStoreIdAll();
            for (int storeId : storeIdList) {
                XxlJobHelper.log("==================== 商城id={} 店铺自动审核开始 ====================", storeId);
                //获取商城设置的删除时间 0 代表永不删除
                mchConfigModel = new MchConfigModel();
                mchConfigModel.setStore_id(storeId);
                mchConfigModel.setMch_id(customerModelMapper.getStoreMchId(storeId));
                mchConfigModel = mchConfigModelMapper.selectOne(mchConfigModel);
                if (mchConfigModel != null && mchConfigModel.getAuto_examine() != 0) {
                    XxlJobHelper.log("====== 商城id={} 设置的时间为{}天店铺自动审核成功 =====", storeId, mchConfigModel.getAuto_examine());
                    Date expireDate = DateUtil.getAddDate(-mchConfigModel.getAuto_examine());
                    //获取当前商城除了自营店其它所有店铺
                    List<Integer> mchIdList = mchModelMapper.getAutoExamineMchId(storeId, expireDate);
                    for (Integer mchId : mchIdList) {
                        XxlJobHelper.log("--------店铺id{}申请时间已超过{}天,系统将自动审核成功---------", mchId, mchConfigModel.getAuto_examine());
                        MchModel mchModel = mchModelMapper.selectByPrimaryKey(mchId);
                        mchModel.setReview_status(DictionaryConst.MchExameStatus.EXAME_PASS_STATUS.toString());
                        mchModelMapper.updateByPrimaryKeySelective(mchModel);
                        XxlJobHelper.log("--------店铺id{}自动审核成功--------", mchId);
                        mchModel = null;
                    }
                } else {
                    XxlJobHelper.log("商城{} 没有设置店铺自动审核天数", storeId);
                }

                XxlJobHelper.log("==================== 店铺自动审核成功 执行完成 ====================");
            }
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail(">>>>>>>店铺自动审核成功处理定时任务 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSJSJFYC, "店铺自动审核成功处理定时任务 异常", "mchAutoExamine");
        } finally {
            storeIdList = null;
            mchConfigModel = null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mchAutoLogOff() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        MchConfigModel mchConfigModel = null;
        JumpPathModel jumpPathModel = null;
        ProductListModel productListModel = null;
        try {
            XxlJobHelper.log("店铺自动注销处理定时任务 开始执行!");
            storeIdList = getStoreIdAll();


            for (int storeId : storeIdList) {
                XxlJobHelper.log("==================== 商城id={} 店铺自动注销开始 ====================", storeId);
                Integer storeMchId = customerModelMapper.getStoreMchId(storeId);
                //获取商城设置的自动注销时间 为0代表无限制
                mchConfigModel = new MchConfigModel();
                mchConfigModel.setStore_id(storeId);
                mchConfigModel.setMch_id(storeMchId);
                mchConfigModel = mchConfigModelMapper.selectOne(mchConfigModel);
                if (mchConfigModel != null && mchConfigModel.getAuto_log_off() > 0) {
                    XxlJobHelper.log("====== 商城id={} 设置的时间为{}个月店铺未登录自动注销 =====", storeId, mchConfigModel.getAuto_log_off());
                    //天数
                    int autoLogOff = mchConfigModel.getAuto_log_off() * 30;
                    String logOffDate = DateUtil.dateFormate(DateUtil.getAddDate(-autoLogOff), GloabConst.TimePattern.YMDHMS);
                    //获取当前商城除了自营店其它所有店铺
                    List<Integer> mchIdList = mchModelMapper.getAutoLogOffMchId(storeId, logOffDate);
                    for (Integer mchId : mchIdList) {
                        //自营店无需注销
                        if (mchId.equals(storeMchId)){
                            continue;
                        }
                        XxlJobHelper.log("--------店铺id{}已超过{}个月未登录,系统将自动注销---------", mchId, mchConfigModel.getAuto_log_off());
                        MchModel mchModel = mchModelMapper.selectByPrimaryKey(mchId);
                        mchModel.setIs_lock(String.valueOf(DictionaryConst.WhetherMaven.WHETHER_OK));
                        mchModelMapper.updateByPrimaryKeySelective(mchModel);
                        //删除跳转地址
                        jumpPathModel = new JumpPathModel();
                        jumpPathModel.setSid(mchModel.getId() + "");
                        jumpPathModel.setType0(JumpPathModel.JumpType.JUMP_TYPE0_MCH);
                        jumpPathModelMapper.delete(jumpPathModel);
                        //删除店铺商品
                        productListModel = new ProductListModel();
                        productListModel.setStore_id(storeId);
                        productListModel.setMch_id(mchId);
                        List<ProductListModel> productListModelList = productListModelMapper.select(productListModel);
                        for (ProductListModel goods : productListModelList) {
                            goods.setStatus(DictionaryConst.GoodsStatus.OFFLINE_GROUNDING.toString());
                            productListModelMapper.updateByPrimaryKeySelective(goods);
                        }
                        //删除对应优惠券
                        couponActivityModelMapper.delCouponByMchId(storeId, mchId);
                    }

                    logOffDate = null;

                } else {
                    XxlJobHelper.log("=======商城{}没有设置店铺自动注销跳过======", storeId);
                    continue;
                }

                XxlJobHelper.log("==================== 商城id={}店铺自动注销执行完成 ====================", storeId);
            }
        } catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail(">>>>>>>店铺自动注销处理定时任务 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSJSJFYC, "店铺自动注销处理定时任务 异常", "mchAutoLogOff");
        } finally {
            storeIdList = null;
            mchConfigModel = null;
            jumpPathModel = null;
            productListModel = null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void storeExpiration() throws LaiKeAPIException {
        List<Integer> storeIdList = null;
        try {
            XxlJobHelper.log("处理商城过期定时任务 开始执行!");
            storeIdList = getStoreIdAll();
            CustomerModel customerModel;
            boolean isExpire = false;
            for (Integer storeId : storeIdList) {
                customerModel = customerModelMapper.selectByPrimaryKey(storeId);
                if (customerModel != null && customerModel.getEnd_date() != null){
                    Date endDate = DateUtil.dateFormateToDate(customerModel.getEnd_date(), GloabConst.TimePattern.YMDHMS);
                    //过期延期7天,超过7天则回收商城
                    Date delayedTime = DateUtil.getAddDate(endDate, 7);
                    //判断是否过期
                    if (DateUtil.dateCompare(new Date(), endDate)) {
                        //标记过期
                        isExpire = true;
                        customerModel.setStatus(CustomerModel.CUSTOMER_STATUS_EXPIRE);
                        XxlJobHelper.log("=======商城id={}已过期======", storeId);
                    }
                    //判断是否需要回收商城
                    if (DateUtil.dateCompare(new Date(), delayedTime)) {
                        //标记过期
                        customerModel.setStatus(CustomerModel.CUSTOMER_STATUS_EXPIRE);
                        XxlJobHelper.log("=======商城id={}超时未缴费,回收商城======", storeId);
                    }
                    if (isExpire) {
                        int count = customerModelMapper.updateByPrimaryKeySelective(customerModel);
                        XxlJobHelper.log("=======商城已过期 处理结果{}======", count > 0);
                        //强制踢出该商城已登录管理员
                        AdminModel adminModel = new AdminModel();
                        adminModel.setStore_id(storeId);
                        adminModel.setRecycle(DictionaryConst.ProductRecycle.NOT_STATUS);
                        List<AdminModel> adminModels = adminModelMapper.select(adminModel);
                        adminModels.forEach(adminModel2 -> {
                            String sidLogKey = GloabConst.RedisHeaderKey.LOGIN_ACCESS_MANAGE_FLAG + adminModel2.getId();
                            String sidTokenOld = redisUtil.get(sidLogKey) + "";
                            if (StringUtils.isNotEmpty(sidTokenOld)) {
                                //踢人
                                XxlJobHelper.log("=======商城id={}已过期,管理员【{}】踢出登录======", storeId, adminModel2.getName());
                                redisUtil.del(sidLogKey);
                                redisUtil.del(sidTokenOld);
                            }
                            sidLogKey = null;
                            sidTokenOld = null;
                        });
                        adminModel = null;
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail(">>>>>>>处理商城过期定时任务 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSJSJFYC, "处理商城过期定时任务 异常", "storeExpiration");
        } finally {
            storeIdList = null;
            XxlJobHelper.handleSuccess("处理商城过期定时任务 开始执行!");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void distributionIncome() {
        List<Integer> storeIdList = null;
        try {
            XxlJobHelper.log("分销系统收益统计报表 开始执行!");
            //获取当前时间
            String dayTime = DateUtil.dateFormate(new Date(), GloabConst.TimePattern.YMD);
            List<UserDistributionModel> userDistributionModels = userDistributionModelMapper.selectAll();
            DistributionIncomeModel distributionIncomeModel = new DistributionIncomeModel();
            for (UserDistributionModel userDistributionModel : userDistributionModels) {
                XxlJobHelper.log("分销商id：" + userDistributionModel.getId());
                if (userDistributionModel.getUplevel() > 0){
                    String user_id = userDistributionModel.getUser_id();
                    Integer store_id = userDistributionModel.getStore_id();
                    //获取记录id
                    Integer id = distributionIncomeModelMapper.getIdByUserIdAndAddTime(store_id, user_id, dayTime);
                    distributionIncomeModel= new DistributionIncomeModel();
                    distributionIncomeModel.setStore_id(store_id);
                    distributionIncomeModel.setUser_id(user_id);
                    //获取当日预估收益
                    distributionIncomeModel.setEstimated_income(distributionRecordModelMapper.sumUserEstimateAmtByAddDate(store_id, user_id, dayTime));
                    //获取当日有效订单
                    distributionIncomeModel.setOrder_num(distributionRecordModelMapper.sumUserOrderNumByAddDate(store_id, user_id, dayTime));
                    //获取有效订单金额
                    distributionIncomeModel.setOrder_price(distributionRecordModelMapper.sumUserOrderTotalByAddDate(store_id, user_id, dayTime));
                    //获取用户单日新增下级
                    distributionIncomeModel.setNew_customer(userDistributionModelMapper.getNewUserNumByAddtime(store_id, user_id, dayTime));
                    //获取当日新增邀请 新增绑定临时关系
                    distributionIncomeModel.setNew_invitation(userDistributionModelMapper.getNewInvitationNumByAddtime(store_id, user_id, dayTime));
                    //全为0不记录
                    if (distributionIncomeModel.getEstimated_income().compareTo(BigDecimal.ZERO) <= 0
                            && distributionIncomeModel.getOrder_num() <= 0
                            && distributionIncomeModel.getOrder_price().compareTo(BigDecimal.ZERO) <= 0
                            && distributionIncomeModel.getNew_customer() <= 0
                            && distributionIncomeModel.getNew_invitation() <= 0){
                        continue;
                    }
                    distributionIncomeModel.setAdd_time(DateUtil.dateFormateToDate(new Date(), GloabConst.TimePattern.YMD));
                    if (id != null){
                        distributionIncomeModel.setId(id);
                        distributionIncomeModelMapper.updateByPrimaryKeySelective(distributionIncomeModel);
                    }else {
                        distributionIncomeModelMapper.insertSelective(distributionIncomeModel);
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail(">>>>>>>分销系统收益统计报表 【异常失败】<<<<<<<", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DSJSJFYC, "分销系统收益统计报表 异常", "storeExpiration");
        } finally {
            storeIdList = null;
            XxlJobHelper.handleSuccess("分销系统收益统计报表 开始执行!");
        }
    }

    @Autowired
    private CouponActivityModelMapper couponActivityModelMapper;

    @Autowired
    private JumpPathModelMapper jumpPathModelMapper;

    @Autowired
    private ConfigModelMapper configModelMapper;

    @Autowired
    private CustomerModelMapper customerModelMapper;

    @Autowired
    private SystemMessageModelMapper systemMessageModelMapper;

    @Autowired
    private TaoBaoModelMapper taoBaoModelMapper;

    @Autowired
    private TaoBaoWorkModelMapper taoBaoWorkModelMapper;

    @Autowired
    private ProductListModelMapper productListModelMapper;

    @Autowired
    private UserBaseMapper userBaseMapper;

    @Autowired
    private AdminModelMapper adminModelMapper;

    @Autowired
    private SkuModelMapper skuModelMapper;

    @Autowired
    private PublicStockService publicStockService;

    @Autowired
    private ConfiGureModelMapper confiGureModelMapper;

    @Autowired
    private StockModelMapper stockModelMapper;

    @Autowired
    private SignRecordModelMapper signRecordModelMapper;

    @Autowired
    private PublicMchService publicMchService;

    @Autowired
    private MchModelMapper mchModelMapper;

    @Autowired
    private MchConfigModelMapper mchConfigModelMapper;

    @Autowired
    private UserDistributionModelMapper userDistributionModelMapper;

    @Autowired
    private DistributionIncomeModelMapper distributionIncomeModelMapper;

    @Autowired
    private DistributionRecordModelMapper distributionRecordModelMapper;
}

